﻿//-----------------------------------------------------------------------
// <copyright file="ChatEngine.cs" company="AFS">
// Copyright (c) AFS. All rights reserved.
//
//    This file is part of Chatbox.
//
//    Chatbox is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    any later version.
//
//    Chatbox is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//    GNU Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public License
//    along with Chatbox. If not, see http://www.gnu.org/copyleft/lesser.html
// </copyright>
//----------------------------------------------------------------------- 

namespace ChatBox.Engine
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using ChatBox.DomainObjects;
    using ChatBox.DomainObjects.ResultData;
    using ChatBox.DomainObjects.Settings;
    using ChatBox.DomainObjects.XmlFeedObjects;
    using ChatBox.Engine.Log;
    using ChatBox.Engine.Web;
    using ChatBox.Interfaces;
    using ChatBox.Utility;

    /// <summary>
    /// Chat engine
    /// </summary>
    public sealed class ChatEngine : IDisposable, IChatEngine
    {
        /// <summary>
        /// E2 account to send notifcations too
        /// </summary>
        private const string NotificationRecipient = "StrawberryFrog";

        /// <summary>
        /// The public messages displayed
        /// </summary>
        private readonly List<Message> publicChatMessages = new List<Message>();

        /// <summary>
        /// The private messages displayed
        /// </summary>
        private readonly List<Message> privateChatMessages = new List<Message>();

        /// <summary>
        /// The other users to display
        /// </summary>
        private readonly List<OtherUser> otherUsers = new List<OtherUser>();

        /// <summary>
        /// New writeups to display
        /// </summary>
        private readonly List<NewWriteup> newWriteups = new List<NewWriteup>();

        /// <summary>
        /// Cool nodes to display
        /// </summary>
        private readonly List<CoolNode> coolNodes = new List<CoolNode>();

        /// <summary>
        /// Editor cools to display
        /// </summary>
        private readonly List<EditorCool> editorCools = new List<EditorCool>();

        /// <summary>
        /// Random nodes to display
        /// </summary>
        private readonly List<Link> randomNodes = new List<Link>();

        /// <summary>
        /// Message deleting
        /// </summary>
        private readonly IMessageDelete messageDelete;

        /// <summary>
        /// Error log destination
        /// </summary>
        private readonly ILogger logger;

        /// <summary>
        /// Random nodes data source
        /// </summary>
        private readonly IRandomNodesSource randomNodesSource;

        /// <summary>
        /// The caption of the random nodes
        /// </summary>
        private string randomNodesWit;

        /// <summary>
        /// Server Settings repository
        /// </summary>
        private IServerSettingsRepository serverSettingsRepository;

        /// <summary>
        /// Uid Settings repository
        /// </summary>
        private IUISettingsRepository uiSettingsRepository;

        /// <summary>
        /// public chat data source
        /// </summary>
        private IPublicChatDataSource publicChatDataSource;
        
        /// <summary>
        /// Source of log on data 
        /// </summary>
        private ILogOnSource logOnSource;

        /// <summary>
        /// Message sending
        /// </summary>
        private IChatMessageSend chatMessageSend;

        /// <summary>
        /// Private chat data source
        /// </summary>
        private IPrivateChatDataSource privateChatDataSource;

        /// <summary>
        /// Other users data source
        /// </summary>
        private IOtherUsersSource otherUsersSource;

        /// <summary>
        /// New writeups data source
        /// </summary>
        private INewWriteupsSource newWriteupsSource;

        /// <summary>
        /// Cool nodes data source
        /// </summary>
        private ICoolNodesSource coolNodesSource;

        /// <summary>
        /// Editor cools data source
        /// </summary>
        private IEditorCoolsSource editorCoolsSource;

        /// <summary>
        /// the public chat topic
        /// </summary>
        private string topic;

        /// <summary>
        /// Initializes a new instance of the ChatEngine class
        /// </summary>
        /// <param name="logger">the logger</param>
        /// <param name="serverSettingsRepository">the server settings</param>
        /// <param name="uiSettingsRepository">the Ui settings</param>
        /// <param name="logOnSource">the login provider</param>
        /// <param name="publicChatDataSource">the public chat data source</param>
        /// <param name="privateChatDataSource">the private chat data source</param>
        /// <param name="otherUsersSource">the other users data source</param>
        /// <param name="chatMessageSend">the chat sending interface</param>
        /// <param name="messageDelete">the message deleting interface</param>
        /// <param name="newWriteupsSource">the new writeups interface</param>
        /// <param name="coolNodesSource">the cool nodes interface</param>
        /// <param name="editorCoolsSource">the editor cools interface</param>
        /// <param name="randomNodesSource">the random nodes interface</param>
        public ChatEngine(
            ILogger logger,
            IServerSettingsRepository serverSettingsRepository,
            IUISettingsRepository uiSettingsRepository,
            ILogOnSource logOnSource,
            IPublicChatDataSource publicChatDataSource,
            IPrivateChatDataSource privateChatDataSource,
            IOtherUsersSource otherUsersSource,
            IChatMessageSend chatMessageSend,
            IMessageDelete messageDelete,
            INewWriteupsSource newWriteupsSource,
            ICoolNodesSource coolNodesSource,
            IEditorCoolsSource editorCoolsSource,
            IRandomNodesSource randomNodesSource)
        {
            this.logger = logger;
            this.serverSettingsRepository = serverSettingsRepository;
            this.uiSettingsRepository = uiSettingsRepository;

            this.publicChatDataSource = publicChatDataSource;
            this.privateChatDataSource = privateChatDataSource;
            this.chatMessageSend = chatMessageSend;
            this.messageDelete = messageDelete;
            this.otherUsersSource = otherUsersSource;

            this.newWriteupsSource = newWriteupsSource;
            this.coolNodesSource = coolNodesSource;
            this.editorCoolsSource = editorCoolsSource;
            this.randomNodesSource = randomNodesSource;

            this.logOnSource = logOnSource;
            this.logOnSource.Completed += this.LogOnCompleted;

            this.publicChatDataSource.DataReceived += this.PublicChatDataReceived;
            this.privateChatDataSource.DataReceived += this.PrivateChatDataReceived;
            this.otherUsersSource.DataReceived += this.OtherUsersSourceDataReceived;

            this.newWriteupsSource.DataReceived += this.NewWriteupsSourceDataReceived;
            this.coolNodesSource.DataReceived += this.CoolNodesSourceDataReceived;
            this.editorCoolsSource.DataReceived += this.EditorCoolsSourceDataReceived;
            this.randomNodesSource.DataReceived += this.RandomNodesSourceDataReceived;

            this.chatMessageSend.Completed += this.ChatMessageSendCompleted;
            this.messageDelete.Completed += this.MessageDeleteCompleted;
        }

        /// <summary>
        /// Notifiation that the title has changed
        /// </summary>
        public event EventHandler TopicChanged;

        /// <summary>
        /// notification that public messages have been received
        /// </summary>
        public event EventHandler PublicMessagesReceived;

        /// <summary>
        /// Notification that private messages have been received
        /// </summary>
        public event EventHandler PrivateMessagesReceived;

        /// <summary>
        /// Notification that an updated version has been received
        /// </summary>
        public event EventHandler<EventArgs<ClientVersion>> UpdatedVersionReceived;

        /// <summary>
        /// Notification of any result from the services
        /// </summary>
        public event EventHandler<EventArgs<OperationResult>> OperationCompleted;

        /// <summary>
        /// Gets the public chat data source
        /// </summary>
        public IPublicChatDataSource PublicChatDataSource
        {
            get
            {
                return this.publicChatDataSource;
            }
        }

        /// <summary>
        /// Gets the private chat data source
        /// </summary>
        public IPrivateChatDataSource PrivateChatDataSource
        {
            get
            {
                return this.privateChatDataSource;
            }
        }

        /// <summary>
        /// Gets the new writeups data source
        /// </summary>
        public INewWriteupsSource NewWriteupsSource
        {
            get
            {
                return this.newWriteupsSource;
            }
        }

        /// <summary>
        /// Gets the cool nodes data source
        /// </summary>
        public ICoolNodesSource CoolNodesSource
        {
            get
            {
                return this.coolNodesSource;
            }
        }

        /// <summary>
        /// Gets the editor cools data source
        /// </summary>
        public IEditorCoolsSource EditorCoolsSource
        {
            get
            {
                return this.editorCoolsSource;
            }
        }

        /// <summary>
        /// Gets the other users data source
        /// </summary>
        public IOtherUsersSource OtherUsersSource
        {
            get
            {
                return this.otherUsersSource;
            }
        }

        /// <summary>
        /// Gets the message deleter
        /// </summary>
        public IMessageDelete MessageDelete
        {
            get
            {
                return this.messageDelete;
            }
        }
        
        /// <summary>
        /// Gets the logger
        /// </summary>
        public ILogger Logger
        {
            get
            {
                return this.logger;
            }
        }

        /// <summary>
        /// Gets the public chat messages
        /// </summary>
        public IList<Message> PublicChatMessages
        {
            get
            {
                return this.publicChatMessages;
            }
        }

        /// <summary>
        /// Gets the private chat messages
        /// </summary>
        public IList<Message> PrivateChatMessages
        {
            get
            {
                return this.privateChatMessages;
            }
        }

        /// <summary>
        /// Gets the other users
        /// </summary>
        public IList<OtherUser> OtherUsers
        {
            get
            {
                return this.otherUsers;
            }
        }

        /// <summary>
        /// Gets the chat topic
        /// </summary>
        public string Topic
        {
            get
            {
                return this.topic;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the user is logged on 
        /// </summary>
        public bool IsLoggedOn
        {
            get
            {
                return this.logOnSource.LogOnCookie != null;
            }
        }

        #region IDisposable Members

        /// <summary>
        /// IDisposable member
        /// </summary>
        public void Dispose()
        {
            this.DisposeInternal();
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Start reading public data
        /// </summary>
        public void StartPublic()
        {
            this.publicChatDataSource.Start();
        }

        /// <summary>
        /// Start the log on 
        /// </summary>
        public void LogOn()
        {
            this.logOnSource.GetLogOn();
        }

        /// <summary>
        /// Start reading private messages
        /// </summary>
        public void StartPrivate()
        {
            if ((this.PrivateChatDataSource != null) && (!this.PrivateChatDataSource.IsStarted))
            {
                this.PrivateChatDataSource.Start();
            }
        }

        /// <summary>
        /// Start the tickers
        /// </summary>
        public void StartTickers()
        {
            if ((this.NewWriteupsSource != null) && (!this.NewWriteupsSource.IsStarted))
            {
                this.NewWriteupsSource.Start();
            }

            if ((this.CoolNodesSource != null) && (!this.CoolNodesSource.IsStarted))
            {
                this.CoolNodesSource.Start();
            }

            if ((this.EditorCoolsSource != null) && (!this.EditorCoolsSource.IsStarted))
            {
                this.EditorCoolsSource.Start();
            }

            if ((this.randomNodesSource != null) && (! this.randomNodesSource.IsStarted))
            {
                this.randomNodesSource.Start();
            }
        }
        
        /// <summary>
        /// Do the disposal
        /// </summary>
        private void DisposeInternal()
        {
            this.privateChatDataSource.TestDispose();
            this.privateChatDataSource = null;

            this.logOnSource.TestDispose();
            this.logOnSource = null;

            this.chatMessageSend.TestDispose();
            this.chatMessageSend = null;

            this.publicChatDataSource.TestDispose();
            this.publicChatDataSource = null;

            this.otherUsersSource.TestDispose();
            this.otherUsersSource = null;

            this.newWriteupsSource.TestDispose();
            this.newWriteupsSource = null;

            this.coolNodesSource.TestDispose();
            this.coolNodesSource = null;

            this.editorCoolsSource.TestDispose();
            this.editorCoolsSource = null;

            this.serverSettingsRepository.TestDispose();
            this.serverSettingsRepository = null;

            this.uiSettingsRepository.TestDispose();
            this.uiSettingsRepository = null;

            this.publicChatMessages.Clear();
            this.privateChatMessages.Clear();
        }

        /// <summary>
        /// notification that public messages have been received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void PublicChatDataReceived(object sender, EventArgs<ChatDataResult> e)
        {
            ChatDataResult chatDataResult = e.Value;

            if (chatDataResult.Success)
            {
                if (chatDataResult.ServerDataType == ServerDataType.Interfaces)
                {
                    this.ReadInterfaces(chatDataResult);
                }
                else
                {
                    this.ReadPublicMessages(chatDataResult);
                }
            }

            this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
        }

        /// <summary>
        /// notification that message sending has completed
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void ChatMessageSendCompleted(object sender, EventArgs<OperationResult> e)
        {
            this.NotifyOperationCompleted(e);
        }

        /// <summary>
        /// notification that deletion has completed
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void MessageDeleteCompleted(object sender, EventArgs<DeleteMessagesDataResult> e)
        {
            if (e.Value.Success)
            {
                // remove private messages as per the deleted ids
                this.privateChatMessages.RemoveAll(m => e.Value.MessageIds.Contains(m.Id));
            }

            this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
        }

        /// <summary>
        /// notification that login has completed
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void LogOnCompleted(object sender, EventArgs<LogOnResult> e)
        {
            this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));

            if (e.Value.Success)
            {
                // send notification if this is the first time this version hs been run
                ServerSettingsData serverSettings = this.serverSettingsRepository.ReadSettings();
                if (serverSettings.LastLogOnVersion < VersionConstants.CurrentVersion)
                {
                    this.NotifyVersionUpdate();
                }

                // send the log
                this.SendErrorLog();
            }
        }

        /// <summary>
        /// Notify that a version update has occured
        /// </summary>
        private void NotifyVersionUpdate()
        {
            ServerSettingsData settingsData = this.serverSettingsRepository.ReadSettings();
            string versionMessage = "Chatbox " + VersionConstants.CurrentVersion + " calling";
            if (settingsData.LastLogOnVersion > 0)
            {
                versionMessage += ". Upgrade from " + settingsData.LastLogOnVersion;
            }

            settingsData.LastLogOnVersion = VersionConstants.CurrentVersion;
            this.serverSettingsRepository.SaveSettings(settingsData);

            this.chatMessageSend.SendMessageTo(NotificationRecipient, versionMessage);
        }

        /// <summary>
        /// send the error log details
        /// </summary>
        private void SendErrorLog()
        {
            const string LogSendMessagePrefix = "Chatbox log: ";
            string logContents = IsolatedStorageLogReader.ReadLog();

            if (! string.IsNullOrEmpty(logContents))
            {
                // send the log and clear it
                this.chatMessageSend.SendMessageTo(NotificationRecipient, LogSendMessagePrefix + logContents);
                IsolatedStorageLogReader.ClearLog();
            }
        }

        /// <summary>
        /// Read interfaces from the data.
        /// Expect to do this once only, on the first result
        /// </summary>
        /// <param name="chatDataResult">the chat data</param>
        private void ReadInterfaces(ChatDataResult chatDataResult)
        {
            // do a version check on the client versions interface
            XmlInterface versionsInterface = chatDataResult.Interfaces.FindByName("clientversions");
            this.StartVersionCheck(versionsInterface);

            // now we can read other users from the other users interface
            XmlInterface otherUsersInterface = chatDataResult.Interfaces.FindByName("otherusers");
            if (otherUsersInterface != null)
            {
                string serverName = this.serverSettingsRepository.ReadSettings().Server;
                Uri otherUsersReadUri = new Uri(serverName + "/node/" + otherUsersInterface.NodeId);
                this.otherUsersSource.ReadUri = otherUsersReadUri;
                if (this.uiSettingsRepository.ReadSettings().ShowOtherUsers)
                {
                    this.OtherUsersSource.Start();
                }
            }

            XmlInterface newWriteupsInterface = chatDataResult.Interfaces.FindByName("newwriteups");
            if (newWriteupsInterface != null)
            {
                this.newWriteupsSource.NodeId = newWriteupsInterface.NodeId;
            }

            XmlInterface coolNodesInterface = chatDataResult.Interfaces.FindByName("coolnodes");
            if (coolNodesInterface != null)
            {                
                this.coolNodesSource.NodeId = coolNodesInterface.NodeId;
            } 
            
            XmlInterface editorCoolsInterface = chatDataResult.Interfaces.FindByName("edcools");
            if (editorCoolsInterface != null)
            {
                this.editorCoolsSource.NodeId = editorCoolsInterface.NodeId;
            }

            XmlInterface randomNodesInterface = chatDataResult.Interfaces.FindByName("random");
            if (randomNodesInterface != null)
            {
                this.randomNodesSource.NodeId = randomNodesInterface.NodeId;
            }
        }

        /// <summary>
        /// Event handler for when other users are received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void OtherUsersSourceDataReceived(object sender, EventArgs<OtherUsersDataResult> e)
        {
            if (e.Value.Success)
            {
                // notify only if the data has changed
                if (! this.OtherUsers.ListSame(e.Value.OtherUsers))
                {
                    this.OtherUsers.Clear();
                    this.otherUsers.AddRange(e.Value.OtherUsers);
                    this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
                }
            }
            else
            {
                this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
            }
        }

        /// <summary>
        /// Kick off the client version check
        /// </summary>
        /// <param name="versionsInterface">the versions interface details</param>
        private void StartVersionCheck(XmlInterface versionsInterface)
        {
            ServerSettingsData settingsData = this.serverSettingsRepository.ReadSettings();
            Uri versionUri = new Uri(settingsData.Server + "/node/" + versionsInterface.NodeId);

            ILatestVersionSource latestVersionSource = new WebLatestVersionSource(versionUri);
            latestVersionSource.Completed += this.LatestVersionCheckCompleted;
            latestVersionSource.GetLatestVersion();
        }

        /// <summary>
        /// latest version check completed
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void LatestVersionCheckCompleted(object sender, EventArgs<ClientLatestVersionResult> e)
        {
            if (e.Value.Success)
            {
                ClientVersion clientVersion = e.Value.LatestVersion;
                decimal serverVersion = clientVersion.LatestVersion.ToDecimal();

                if (serverVersion > VersionConstants.CurrentVersion)
                {
                    this.NotifyUpdatedVersionReceived(clientVersion);
                }
            }

            this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
        }

        /// <summary>
        /// Read public messages from the data
        /// </summary>
        /// <param name="chatDataResult">the chat data</param>
        private void ReadPublicMessages(ChatDataResult chatDataResult)
        {
            if ((chatDataResult.Messages != null) && (chatDataResult.Messages.Count() > 0))
            {
                this.publicChatMessages.AddNewMessages(chatDataResult.Messages);

                ServerSettingsData serverSettingsData = this.serverSettingsRepository.ReadSettings();
                this.publicChatMessages.RemoveExcessMessages(serverSettingsData.MaxPublicMessagesKept);

                this.NotifyPublicMessagesReceived();
            }

            if (!string.Equals(this.topic, chatDataResult.Topic, StringComparison.OrdinalIgnoreCase))
            {
                this.topic = chatDataResult.Topic;
                this.NotifyTopicChanged();
            }
        }

        /// <summary>
        /// notification that private messages have been received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void PrivateChatDataReceived(object sender, EventArgs<ChatDataResult> e)
        {
            ChatDataResult chatDataResult = e.Value;
            if (chatDataResult.Success)
            {
                if ((chatDataResult.Messages != null) && (chatDataResult.Messages.Count() > 0))
                {
                    this.privateChatMessages.AddNewMessages(chatDataResult.Messages);
                    this.NotifyPrivateMessagesReceived();
                }
            }

            this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
        }

        /// <summary>
        /// Notification that editor cools have been received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void EditorCoolsSourceDataReceived(object sender, EventArgs<EditorCoolsDataResult> e)
        {
            if (e.Value.Success)
            {
                if (!this.editorCools.ListSame(e.Value.EditorCools))
                {
                    this.editorCools.Clear();
                    this.editorCools.AddRange(e.Value.EditorCools);
                    this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
                }
            }
            else
            {
                this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
            }
        }

        /// <summary>
        /// Notification that random nodes have been received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void RandomNodesSourceDataReceived(object sender, EventArgs<RandomNodesDataResult> e)
        {
            if (e.Value.Success)
            {
                if (!this.randomNodes.ListSame(e.Value.RandomNodes) || 
                    ! (this.randomNodesWit == e.Value.Wit))
                {
                    this.randomNodes.Clear();
                    this.randomNodes.AddRange(e.Value.RandomNodes);
                    this.randomNodesWit = e.Value.Wit;

                    this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
                }
            }
            else
            {
                this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
            }
        }        

        /// <summary>
        /// Notification that cool nodes have been received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void CoolNodesSourceDataReceived(object sender, EventArgs<CoolNodesDataResult> e)
        {
            if (e.Value.Success)
            {
                if (!this.coolNodes.ListSame(e.Value.CoolNodes))
                {
                    this.coolNodes.Clear();
                    this.coolNodes.AddRange(e.Value.CoolNodes);
                    this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
                }
            }
            else
            {
                this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
            } 
        }

        /// <summary>
        /// Notification that new writeups have been received
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void NewWriteupsSourceDataReceived(object sender, EventArgs<NewWriteupsDataResult> e)
        {
            if (e.Value.Success)
            {
                if (! this.newWriteups.ListSame(e.Value.NewWriteups))
                {
                    this.newWriteups.Clear();
                    this.newWriteups.AddRange(e.Value.NewWriteups);
                    this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));
                }
            }
            else
            {
                this.NotifyOperationCompleted(new EventArgs<OperationResult>(e.Value));                
            }
        }

        /// <summary>
        /// Send notification that the topic has changed
        /// </summary>
        private void NotifyTopicChanged()
        {
            if (this.TopicChanged != null)
            {
                this.TopicChanged(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Send notification that there are public messages
        /// </summary>
        private void NotifyPublicMessagesReceived()
        {
            if (this.PublicMessagesReceived != null)
            {
                this.PublicMessagesReceived(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Send notification that there are private messages
        /// </summary>
        private void NotifyPrivateMessagesReceived()
        {
            if (this.PrivateMessagesReceived != null)
            {
                this.PrivateMessagesReceived(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Send notification that an updated version exists
        /// </summary>
        /// <param name="clientVersion">the new version</param>
        private void NotifyUpdatedVersionReceived(ClientVersion clientVersion)
        {
            if (this.UpdatedVersionReceived != null)
            {
                this.UpdatedVersionReceived(this, new EventArgs<ClientVersion>(clientVersion));
            }
        }

        /// <summary>
        /// Send notification that an operation has completed with sucess or error
        /// </summary>
        /// <param name="e">the event args containing result data from the operation</param>
        private void NotifyOperationCompleted(EventArgs<OperationResult> e)
        {
            if (this.OperationCompleted != null)
            {
                this.OperationCompleted(this, e);
            }
        }

        #endregion
    }
}
